//
//  BDFMDBTool.m
//  BadBoy
//
//  Created by wen on 2017/1/11.
//  Copyright © 2017年 niusaibing. All rights reserved.
//

#import "BDFMDBTool.h"
#import <objc/runtime.h>

@interface BDFMDBTool ()

//@property (nonatomic, strong) FMDatabase *db;

@property (nonatomic, strong) FMDatabaseQueue *queue;

//用来装表明和对应class的关系
@property (nonatomic, strong) NSMutableDictionary *tableDic;

//获取一个类的属性数组
+ (NSArray *)getmembersWithClass:(Class)newClass;

//根据属性数组创建一个类
+ (BOOL)creatWithKeyArray:(NSArray *)array tableName:(NSString *)tableName db:(FMDatabase *)db;

@end

@implementation BDFMDBTool
+ (instancetype)sharedTool{
    static BDFMDBTool *tool;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (tool == nil) {
            tool = [[self alloc] init];
        }
    });
    return tool;
}

+ (void)creatWithClass:(Class)newClass tableName:(NSString *)tableName{
    [self creatWithClass:newClass tableName:tableName primaryKey:nil];
}

+ (void)creatWithClass:(Class)newClass tableName:(NSString *)tableName primaryKey:(NSString *)primaryKey{
    BDFMDBTool *tool = [BDFMDBTool sharedTool];
    [tool.queue inDatabase:^(FMDatabase *db) {
        if ([db open]){
            BOOL result = YES;
            
            NSArray *memberArr = [self getmembersWithClass:newClass];
            result = [self creatWithKeyArray:memberArr tableName:tableName db:db primaryKey:primaryKey];
            if (result == YES) {
                [tool.tableDic setObject:tableName forKey:NSStringFromClass(newClass)];
            }else{
//                // BDLog(ASLocalizedString(@"创建数据库失败"));
            }
            [db close];
            BOOL save = [tool.tableDic writeToFile:kTableNamePath atomically:YES];
        }
    }];
}

+ (NSArray *)getmembersWithClass:(Class)newClass{
    unsigned int count = 0;
    //获取属性列表
    Ivar *members = class_copyIvarList(newClass, &count);
    NSMutableArray *newArray = [NSMutableArray array];
    for (int i = 0 ; i < count; i++) {
        Ivar var = members[i];
        //获取变量名称
        const char *memberName = ivar_getName(var);
        //获取变量类型
        NSString *nameStr = [NSString stringWithCString:memberName encoding:NSUTF8StringEncoding];
        [newArray addObject:[nameStr substringFromIndex:1]];
    }
    return newArray;
}

+ (BOOL)yy_executeUpdateWithString:(NSString *)string db:(FMDatabase *)db{
    return [db executeUpdate:string];
}

//创建表  所有字段保存为text类型
+ (BOOL)creatWithKeyArray:(NSArray *)array tableName:(NSString *)tableName db:(FMDatabase *)db primaryKey:(NSString *)primaryKey{
    NSMutableArray *newArray = array.mutableCopy;
    NSString *str = @"id integer primary key autoincrement";
    if ([primaryKey isNotEmpty]) {
        for (NSString *key in array) {
            if ([key isEqualToString:primaryKey]) {
                str = [NSString stringWithFormat:@"%@ text primary key", primaryKey];
                [newArray removeObject:primaryKey];
                break;
            }
        }
    }
    for (int i = 0; i < newArray.count; i++) {
        str = [str stringByAppendingString:[NSString stringWithFormat:@", %@ text", newArray[i]]];
    }
    NSString *sqlString = [NSString stringWithFormat:@"create table if not exists %@ (%@);", tableName, str];
    BOOL result = [self yy_executeUpdateWithString:sqlString db:db];
    return result;
    return NO;
}


//插入一个对象
+ (void)insertWithObject:(id)object{
    [self insertWithObjectsArray:@[object]];
}

+ (void)insertWithObjectsArray:(NSArray *)objectsArray{
//    // BDLog(ASLocalizedString(@"插入数据库操作"));
    //首先获取当前对象的类型，判断是否存在于字典中
    Class currentClass = [objectsArray.firstObject class];
    NSString *tableName = [self getTableNameWithClassName:currentClass];
    if (tableName) {
        //先判断数据库是否可用
        BDFMDBTool *tool = [self sharedTool];
        [tool.queue inDatabase:^(FMDatabase *db) {
            if ([db open]){
                BOOL result = YES;
                for (id object in objectsArray) {
                    NSString *sqlString = [NSString stringWithFormat:@"insert into %@ %@;",tableName, [self creatSqlWithObject:object]];
                    result = [self yy_executeUpdateWithString:sqlString db:db];
                    if (result == NO) {
                        break;
                    }else{
                    }
                }
                
                [db close];
            }
        }];
    }
}

+ (void)replaceWithObject:(id)object{
    [self replaceWithObjectsArray:@[object]];
}

+ (void)replaceWithObjectsArray:(NSArray *)objectsArray{
//    // BDLog(ASLocalizedString(@"插入数据库操作"));
    //首先获取当前对象的类型，判断是否存在于字典中
    Class currentClass = [objectsArray.firstObject class];
    NSString *tableName = [self getTableNameWithClassName:currentClass];
    if (tableName) {
        //先判断数据库是否可用
        BDFMDBTool *tool = [self sharedTool];
        [tool.queue inDatabase:^(FMDatabase *db) {
            if ([db open]){
                
                [db beginTransaction];
                BOOL isRollBack = NO;
                @try {
                    for (id object in objectsArray) {
                        NSString *sqlString = [NSString stringWithFormat:@"replace into %@ %@;",tableName, [self creatSqlWithObject:object]];
                        BOOL result = [self yy_executeUpdateWithString:sqlString db:db];
                        if (result == NO) {
//                            // BDLog(ASLocalizedString(@"插入失败"));
                            continue;
                        }
                    }
                }
                @catch (NSException *exception) {
                    isRollBack = YES;
                    [db rollback];
                }
                @finally {
                    if (!isRollBack) {
                        [db commit];
                    }
                }
                [db close];
            }
        }];
    }
}

//获取对象属性和值组合成的SQL语句
+ (NSString *)creatSqlWithObject:(id)object{
    Class obClass = [object class];
    
    NSArray *keys = [self getmembersWithClass:obClass];
    
    NSMutableArray *keyArray = [NSMutableArray array];
    NSMutableArray *valuesArray = [NSMutableArray array];
    for (NSString * key in keys) {
        NSString *value = [object valueForKeyPath:key];
        if (![value isNotEmpty]) {
            value = @"";
        }
        if ([value containsString:@"'"]) {
            value = [value stringByReplacingOccurrencesOfString:@"'" withString:@"''"];
        }
        [keyArray addObject:key];
        [valuesArray addObject:[NSString stringWithFormat:@"'%@'", value]];
    }
    
    NSString *str1 = [keyArray componentsJoinedByString:@", "];
    NSString *str2 = [valuesArray componentsJoinedByString:@", "];
    return [NSString stringWithFormat:@"(%@) values (%@)", str1, str2];
}

+ (NSString *)getTableNameWithClassName:(Class)className{
    BDFMDBTool *tool = [BDFMDBTool sharedTool];
    return tool.tableDic[NSStringFromClass(className)];
}

+ (void)deleteWithObject:(id)object{
    if (object == nil) {
        return;
    }
    [self deleteWithObjectsArray:@[object]];
}

+ (void)deleteWithObjectsArray:(NSArray *)objectsArray{
//    // BDLog(ASLocalizedString(@"删除数据库操作"));
    if (objectsArray.count == 0) {
        return;
    }
    Class curClass = [objectsArray.firstObject class];
    NSString *tableName = [self getTableNameWithClassName:curClass];
    if (tableName) {
        //先判断数据库是否可用
        BDFMDBTool *tool = [self sharedTool];
        [tool.queue inDatabase:^(FMDatabase *db){
            if ([db open]){
                for (int i = 0; i < objectsArray.count; i++) {
                    NSString *sqlString = [NSString stringWithFormat:@"delete from %@ where %@", tableName, [self getKeyValueCombinString:objectsArray[i]]];
                    BOOL result = [self yy_executeUpdateWithString:sqlString db:db];
                }
                [db close];
            }
        }];
    }
}

+ (void)deleteTableWithClass:(Class)tableClass{
//    // BDLog(ASLocalizedString(@"删除数据库操作"));
    NSString *tableName = [self getTableNameWithClassName:tableClass];
    NSString *sqlString = [NSString stringWithFormat:@"delete from %@;",tableName];
    BDFMDBTool *tool = [self sharedTool];
    [tool.queue inDatabase:^(FMDatabase *db) {
        if ([db open]){
            //根据语句获取到相应的集合
            BOOL result = [self yy_executeUpdateWithString:sqlString db:db];
            [db close];
        }
    }];
}

+ (NSArray *)queryWithClass:(Class)obClass{
//    // BDLog(ASLocalizedString(@"查询数据库操作"));
    NSString *tableName = [self getTableNameWithClassName:obClass];
    NSString *sqlString = [NSString stringWithFormat:@"select * from %@;",tableName];
    BDFMDBTool *tool = [self sharedTool];
    __block NSMutableArray *draftInfoArray = [[NSMutableArray alloc] init];
    [tool.queue inDatabase:^(FMDatabase *db) {
        if ([db open]){
            //根据语句获取到相应的集合
            FMResultSet *rs = [db executeQuery:sqlString];
            NSArray *keyArr = [self getmembersWithClass:obClass];
            //根据class创建对象，根据KVC重新修改值
            while (rs.next) {
                id resObject = [[obClass alloc] init];
                for (NSString *key in keyArr) {
                    [resObject setValue:[rs stringForColumn:key] forKeyPath:key];
                }
                [draftInfoArray addObject:resObject];
            }
            [db close];
        }
    }];
    return draftInfoArray;
}

+ (NSArray *)queryWithClass:(Class)obClass condition:(NSString *)condition{
//    // BDLog(ASLocalizedString(@"查询数据库操作"));
    NSString *tableName = [self getTableNameWithClassName:obClass];
    NSString *sqlString = [NSString stringWithFormat:@"select * from %@ where %@;",tableName, condition];
    BDFMDBTool *tool = [self sharedTool];
    __block NSMutableArray *draftInfoArray = [[NSMutableArray alloc] init];
    [tool.queue inDatabase:^(FMDatabase *db) {
        if ([db open]){
            //根据语句获取到相应的集合
            FMResultSet *rs = [db executeQuery:sqlString];
            NSArray *keyArr = [self getmembersWithClass:obClass];
            //根据class创建对象，根据KVC重新修改值
            while (rs.next) {
                id resObject = [[obClass alloc] init];
                for (NSString *key in keyArr) {
                    [resObject setValue:[rs stringForColumn:key] forKeyPath:key];
                }
                [draftInfoArray addObject:resObject];
            }
            [db close];
        }
    }];
    return draftInfoArray;
}

+ (void)updateOldObject:(id)oldObject newObject:(id)newObject{
    NSString *tableName = [self getTableNameWithClassName:[newObject class]];
    if (tableName) {
        //先判断数据库是否可用
        BDFMDBTool *tool = [self sharedTool];
        [tool.queue inDatabase:^(FMDatabase *db){
            if ([db open]){
                //更新的话需要旧数据和新数据做对比，然后根据旧数据取到id，然后在把新数据拼接
                NSString *sqlString = [NSString stringWithFormat:@"update %@ set %@ where %@", tableName, [self getKeyValueCombinString:newObject], [self getKeyValueCombinString:oldObject]];
                BOOL result = [self yy_executeUpdateWithString:sqlString db:db];
                [db close];
            }
        }];
    }
}

+ (void)updateObject:(id)object condition:(NSString *)condition{
    NSString *tableName = [self getTableNameWithClassName:[object class]];
    if (tableName) {
        //先判断数据库是否可用
        BDFMDBTool *tool = [self sharedTool];
        [tool.queue inDatabase:^(FMDatabase *db){
            if ([db open]){
                //更新的话需要旧数据和新数据做对比，然后根据旧数据取到id，然后在把新数据拼接
                NSString *sqlString = [NSString stringWithFormat:@"update %@ %@", tableName, condition];
                BOOL result = [self yy_executeUpdateWithString:sqlString db:db];
                [db close];
            }
        }];
    }
}

//将对象的值修改为字段和值对应的状态
+ (NSString *)getKeyValueCombinString:(id)object{
    NSArray *memberArr = [self getmembersWithClass:[object class]];
    NSString *str = @"";
    for (int i = 0; i < memberArr.count; i++) {
        NSString *value = [object valueForKeyPath:memberArr[i]];
        if (![value isNotEmpty]) {
            value = @"";
        }
        if (i == 0) {
            str = [str stringByAppendingString:[NSString stringWithFormat:@"%@ = '%@'", memberArr[i], value]];
        }else{
            str = [str stringByAppendingString:[NSString stringWithFormat:@" and %@ = '%@'", memberArr[i], value]];
        }
    }
    return str;
}

- (FMDatabaseQueue *)queue{
    if (!_queue) {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docPath = [paths lastObject];
        NSString *sqlitePath = [docPath stringByAppendingPathComponent:@"BadBoy.sqlite"];
        self.queue = [[FMDatabaseQueue alloc] initWithPath:sqlitePath];
    }
    return _queue;
}

- (NSMutableDictionary *)tableDic{
    if (!_tableDic) {
        self.tableDic = [NSMutableDictionary dictionaryWithContentsOfFile:kTableNamePath];
        if (_tableDic == nil) {
            _tableDic = [NSMutableDictionary dictionary];
        }
    }
    return _tableDic;
}

@end
